from collections import defaultdict


def naive_insert_sqls(data_list, database, batch_size=10000):
    """
    生成插入sql
    body = {
        "equipment_uid": "138488484",
        "equipment_part_uid": "1284848",
        "parameter_uid": "temp_FM",
        "type": "float",  # 数值型是float，列表是list，此接口只支持float
        "timestamp": 1609434061000,   # 精确到ms
        "value": "111" # 是str型
    }
    :return:
        True or False
    """
    sqls = []
    table_data = defaultdict(list)
    table_tags = {}
    for d in data_list:
        eq_uid = d["equipment_uid"].lower()
        part_uid = d['equipment_part_uid'].lower()
        param_uid = d['parameter_uid'].lower()
        table = f"ts_{part_uid}_{param_uid}"
        tb = f"{database}.{table}"
        stb = f"{database}.{param_uid}"
        key = (tb, stb)
        tags = {
            "eq_uid": eq_uid,
            "part_uid": part_uid
        }

        if d["type"] in ["list"]:
            tag_names = f"({', '.join(list(tags.keys()))})"
            str_tag_values = ["'{}'".format(v) for v in tags.values()]
            tag_values = f"({', '.join(str_tag_values)})"
            # tag_values = f"({', '.join(list(map(str, tags.values())))})"
            tgs = f"{tag_names} tags {tag_values}"

            points = []
            ts = d["timestamp"]
            for i, v in enumerate(eval(d["value"])):
                point = (ts, "now", int(d["timestamp"] / 1000), i + 1, v)
                points.append(point)
                ts += 1

            for i in range(0, len(points), batch_size):
                data = points[i:i + batch_size]
                vs = " ".join(map(str, data)). \
                    replace("'", "").replace('"', "")
                sql = f"insert into {tb} using {stb} {tgs} values {vs};"
                sqls.append(sql)
            continue

        table_tags[key] = tags
        table_data[key].append((d["timestamp"], "now", float(d["value"])))

    for (tb, stb), points in table_data.items():
        for i in range(0, len(points), batch_size):
            data = points[i:i + batch_size]
            tags = table_tags[(tb, stb)]
            tag_names = f"({', '.join(list(tags.keys()))})"
            str_tag_values = ["'{}'".format(v) for v in tags.values()]
            tag_values = f"({', '.join(str_tag_values)})"
            # tag_values = f"({', '.join(list(map(str, tags.values())))})"
            tgs = f"{tag_names} tags {tag_values}"
            vs = " ".join(map(str, data)).replace("'", "").replace('"', "")
            sql = f"insert into {tb} using {stb} {tgs} values {vs};"
            sqls.append(sql)
    return sqls


def create_stables(self, tables, columns, tags, database=None):
    db = database if database else self.database
    if not db:
        raise Exception("'database' must be provided when init or call")

    existed_tables = self.show_stables(db)
    cols = ", ".join([f"{'`'+_['field']+'`' if _['field'] == 'value' else _['field']} {_['type']}" for _ in columns])
    cols = f"(ts TIMESTAMP, {cols})"
    tgs = f'tags ({", ".join(["%s nchar(20)" % tag for tag in tags])})'
    sqls = []
    for table in tables:
        tb = table.lower()
        if tb in existed_tables:
            continue
        tb = f"{db}.{tb}"
        sql = f"create stable {tb} {cols} {tgs};"
        sqls.append(sql)
    # print(sqls)
    if not sqls:
        return True
    res = self.async_query(sqls)
    if not res:
        return False
    for k, v in res.items():
        if not v:
            return False
        if v["code"] != 0:
            return False
    return True


def create_series_stables(tables, columns=[], tags=[],
                          database=None):
    default_columns = [
        {"field": "inserted_at", "type": "timestamp"},
        {"field": "value", "type": "float"}
    ]
    default_tags = ["eq_uid", "part_uid"]
    return create_stables(
        tables,
        columns if columns else default_columns,
        tags if tags else default_tags,
        database
    )